package main

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"github.com/elazarl/goproxy"
	//"github.com/elazarl/goproxy/transport"
)

func main2() {
	// tcp 连接，监听 8080 端口
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Panic(err)
	}

	// 死循环，每当遇到连接时，调用 handle
	for {
		client, err := l.Accept()
		if err != nil {
			log.Panic(err)
		}

		go handle(client)
	}
}

func handle(client net.Conn) {
	if client == nil {
		return
	}
	defer client.Close()

	log.Printf("remote addr: %v\n", client.RemoteAddr())

	// 用来存放客户端数据的缓冲区
	var b [1024]byte
	//从客户端获取数据
	n, err := client.Read(b[:])
	if err != nil {
		log.Println(err)
		return
	}

	log.Printf("remote addr222: %v\n", (string)(b[:n]))

	var method, URL, address string
	// 从客户端数据读入 method，url
	fmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &URL)
	hostPortURL, err := url.Parse(URL)
	if err != nil {
		log.Println(err)
		return
	}

	// 如果方法是 CONNECT，则为 https 协议
	if method == "CONNECT" {
		address = hostPortURL.Scheme + ":" + hostPortURL.Opaque
	} else { //否则为 http 协议
		address = hostPortURL.Host
		// 如果 host 不带端口，则默认为 80
		if strings.Index(hostPortURL.Host, ":") == -1 { //host 不带端口， 默认 80
			address = hostPortURL.Host + ":80"
		}
	}

	log.Printf("service url:%v addr:  %v\n", URL, address)

	//获得了请求的 host 和 port，向服务端发起 tcp 连接
	server, err := net.Dial("tcp", address)
	if err != nil {
		log.Println(err)
		return
	}
	//如果使用 https 协议，需先向客户端表示连接建立完毕
	if method == "CONNECT" {
		fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n\r\n")
	} else { //如果使用 http 协议，需将从客户端得到的 http 请求转发给服务端
		server.Write(b[:n])
	}

	//将客户端的请求转发至服务端，将服务端的响应转发给客户端。io.Copy 为阻塞函数，文件描述符不关闭就不停止
	go func(dst io.Writer, src io.Reader) {
		io.Copy(server, client)
	}(server, client)

	io.Copy(client, server)
}

func main() {
	verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") // 设置是否输出连接信息
	addr := flag.String("addr", ":8080", "proxy listen address")                       // 监听端口和地址
	flag.Parse()
	proxy := goproxy.NewProxyHttpServer()
	pwd, _ := os.Getwd()
	caCert, err := ioutil.ReadFile(pwd + "/cert.pem") // 设置为你刚才生成的证书路径
	if err != nil {
		log.Fatal(err)
	}
	caKey, err := ioutil.ReadFile(pwd + "/key.pem") // 设置为你刚才生成的证书路径
	SetCA(caCert, caKey)
	proxy.Verbose = *verbose
	proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)

	// 监听来自 qq.com 的响应 并在里面做出自己的处理动作
	proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
		//if resp.Request.Host == "qq.com" {

		/*	respCopy := *resp
			resBody, _ := io.ReadAll(respCopy.Body)
		*/
		//	log.Println("fdfdf", string(resBody))
		//}
		buf := new(bytes.Buffer)
		buf.ReadFrom(resp.Body)
		resp.Body = ioutil.NopCloser(bytes.NewBuffer(buf.Bytes()))

		log.Println("fdfdf", string(buf.Bytes()), resp.Request.URL)
		return resp
	})
	l, err := net.Listen("tcp", *addr)
	if err != nil {
		log.Fatal("listen:", err)
	}

	log.Println("Starting Proxy")
	http.Serve(l, proxy)
}

func SetCA(caCert, caKey []byte) error {
	goproxyCa, err := tls.X509KeyPair(caCert, caKey)
	if err != nil {
		return err
	}
	if goproxyCa.Leaf, err = x509.ParseCertificate(goproxyCa.Certificate[0]); err != nil {
		return err
	}
	goproxy.GoproxyCa = goproxyCa
	goproxy.OkConnect = &goproxy.ConnectAction{Action: goproxy.ConnectAccept, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
	goproxy.MitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
	goproxy.HTTPMitmConnect = &goproxy.ConnectAction{Action: goproxy.ConnectHTTPMitm, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
	goproxy.RejectConnect = &goproxy.ConnectAction{Action: goproxy.ConnectReject, TLSConfig: goproxy.TLSConfigFromCA(&goproxyCa)}
	return nil
}
